;===============================================================================
; XY AUTO SQUARING CALIBRATION MACRO
;===============================================================================
; Purpose: Automatically measure bed hole positions and calculate axis scaling
;          corrections and squareness compensation for IDEX printers
;===============================================================================

if !exists(param.A)
  M291 S1 T0 R"Use Auto Calibration macro" P"Using separate calibration macros may cause issues.<br>Please use the Auto Calibration macro"
  abort "Error: Auto Calibration macro required."


;===============================================================================
; SECTION 1: INITIAL CONFIGURATION
;===============================================================================

; ===== Bed Hole Center Coordinates (adjust these to match your measured values) =====
var LR = {-150.1, 159.7}        ; U, Y  |  Left Rear Hole Center Coordinates
var RR = {149.5, 161.2}         ; U, Y  |  Right Rear Hole Center Coordinates
var RF = {150.7, -158.3}        ; U, Y  |  Right Front Hole Center Coordinates

; ===== Probing Configuration Variables =====
var holecoor = {0, 0, 0, 0}     ; UL, UR, YF, YR,  |  Border Coordinates of the Hole
var hole_Z_Test_Offset = 15     ; Z Offset for safe probe dive test
var max_Travel = 15             ; Maximum travel distance when searching for hole edges
var prevXySquareAuto = 0.0      ; Store previous auto squaring value
var prevXySquareManual = 0.0    ; Store old manual squaring value
var Z_Tilt = 3                  ; Z lift for bed tilt compensation
var Z_Clearance = 3             ; Safe Z clearance height
var Z_Dive = 0.5                ; Depth to dive into hole for verification

; ===== Load Global Variables =====
M98 P"0:/sys/user/actions/ProbeOffset.g"

; ===== Initialize Squaring Variables =====

set var.prevXySquareManual = global.xySquareManual
set global.xySquareManual = 0.0

set var.prevXySquareAuto = global.xySquareAuto
set global.xySquareAuto = 0.0

var xyActive = global.xySquareManual
if global.xySquareMode != "manual"
  set var.xyActive = global.xySquareAuto

; ===== Safety Check - Verify Probe is Detached =====
M98 P"0:/sys/detachedcheck.g"

G28 Y   ; Home Y axis
G28 X   ; Home X axis
G28 U   ; Home U axis


;===============================================================================
; SECTION 2: BED PREPARATION
;===============================================================================

; ===== Tilt Bed for Access =====
M584 Z1.2                       ; Temporarily use only one Z motor for tilting
G91                             ; Relative positioning
G1 Z{var.Z_Tilt} F18000         ; Lift bed by tilt amount
G90                             ; Absolute positioning
M584 Z1.0:1.1:1.2               ; Restore all three Z motors
M906 X1800 U1800 Y1800:1800 Z850 E600:600 I35 T10
M913 Z100                       ; Restore Z motor current to 100%

; ===== Configure Probe for Contact Detection =====
M558 K0 P8 C"1.io4.in" H5 F600 T18000  ; Configure nozzle contact probe
M98 P"0:/sys/nozzlewipe.g" T1         ; Optional: clean nozzle before probing




;===============================================================================
; SECTION 3: LEFT REAR HOLE PROBING
;===============================================================================

; ===== Step 3.1: Obtain Z Datum for Left Rear Hole =====
G1 U{var.LR[0]} Y{var.LR[1] - var.hole_Z_Test_Offset} Z{var.Z_Clearance} F18000

M98 P"0:/sys/nozzleprobe.g" Z10
G4 P300
var T1_Ref_Z = move.axes[2].userPosition

G90                                                    ; Absolute

G1 Z{var.T1_Ref_Z + 1} F6000                           ; Lift 1mm above bed surface
G1 Y{var.LR[1]} U{var.LR[0]} F6000                ; Move to the hole center position

; ===== Step 3.2: Left Rear Hole Center Positioning Test =====
; Test if nozzle is positioned above hole by attempting to dive into it
M558 K0 P8 C"1.io4.in" H5 F60 T18000               ; Configure probe: slow speed for safe diving
G38.4 K0 Z{var.T1_Ref_Z - var.Z_Dive} F60                 ; Attempt to dive 0.5mm below bed surface into hole

if result == 0  ; result==0 means probe did NOT trigger (hit bed surface, not in hole)
  ; Nozzle hit bed surface outside hole - not positioned correctly
  M98 P"0:/sys/led/pause.g"
  G90
  G1 Z{var.T1_Ref_Z + 1} F6000
  M291 R"Position Nozzle Above Hole" P"Nozzle is not positioned above the hole. Manually position the nozzle directly above the rear left hole center using U/Y jog controls." S3 U1 Y1
  
  ; Verify user positioned correctly by testing dive again
  M558 K0 P8 C"1.io4.in" H5 F60 T18000             ; Configure probe for verification
  G38.4 K0 Z{var.T1_Ref_Z - 1.0} F60               ; Dive deeper (1mm below surface) to verify
  if result == 0
    ; Still hitting surface outside hole - abort
    M98 P"0:/sys/led/fault.g"
    abort "Error: Nozzle still not positioned correctly above hole. Please check alignment."
  else
    ; Successfully positioned - update coordinates
    M98 P"0:/sys/led/resetstatus.g"
    G4 P300
    set var.LR[0] = move.axes[3].userPosition
    set var.LR[1] = move.axes[1].userPosition
else
  ; Nozzle went into hole successfully - already positioned correctly
  M98 P"0:/sys/led/resetstatus.g"
  G4 P300
  set var.LR[0] = move.axes[3].userPosition
  set var.LR[1] = move.axes[1].userPosition


; ===== Step 3.3: Left Rear Hole Center Searching (4-Direction Probing) =====
; Probe all 4 edges of the hole (YF, YR, UL, UR) to find precise center
; Repeats twice for accuracy refinement
M558 K0 P8 C"1.io4.in" H5 F60 T18000              ; define Z probe parameters
M98 P"0:/sys/user/actions/ProbeOffset.g"

var iteration = 0
while var.iteration < 2
  G90
  G1 U{var.LR[0]} Y{var.LR[1]} F6000
  
  ; 1st Probe - YF (Y Front/Negative)
  G38.4 K0 Y{move.axes[1].userPosition - var.max_Travel}
  M400
  G4 P300
  set var.holecoor[2] = move.axes[1].userPosition
  G1 Y{var.LR[1]} F6000
  
  ; 2nd Probe - YR (Y Rear/Positive)
  G38.4 K0 Y{move.axes[1].userPosition + var.max_Travel}
  M400
  G4 P300
  set var.holecoor[3] = move.axes[1].userPosition
  
  set var.LR[1] = {var.holecoor[2] + var.holecoor[3]} / 2 ; LRy center coordinate
  G1 Y{var.LR[1]} F6000
  
  ; 3rd Probe - UL (U Left/Negative)
  G38.4 K0 U{move.axes[3].userPosition - var.max_Travel}
  M400
  G4 P300
  set var.holecoor[0] = move.axes[3].userPosition
  G1 U{var.LR[0]} F6000
  
  ; 4th Probe - UR (U Right/Positive)
  G38.4 K0 U{move.axes[3].userPosition + var.max_Travel}
  M400
  G4 P300
  set var.holecoor[1] = move.axes[3].userPosition
  
  set var.LR[0] = {var.holecoor[0] + var.holecoor[1]} / 2 ; LRx center coordinate
  
  echo "=== Iteration " ^ {var.iteration + 1} ^ " Complete ==="
  echo "  holecoor[0] (UL) = " ^ var.holecoor[0]
  echo "  holecoor[1] (UR) = " ^ var.holecoor[1]
  echo "  holecoor[2] (YF) = " ^ var.holecoor[2]
  echo "  holecoor[3] (YR) = " ^ var.holecoor[3]
  echo "  LR[0] (U center) = " ^ var.LR[0]
  echo "  LR[1] (Y center) = " ^ var.LR[1]
  echo ""
  
  set var.iteration = var.iteration + 1

G90
M400
; ===== Step 3.4: Move Away from Left Rear Hole =====
G90
M400
G1 Y{var.LR[1]} U{var.LR[0]} F18000                      ; Move to final calculated center
G4 S1                                                      ; Wait 1 second
G1 Z{var.T1_Ref_Z + var.Z_Tilt+var.Z_Clearance} F18000   ; Lift to safe height


;===============================================================================
; SECTION 4: RIGHT REAR HOLE PROBING
;===============================================================================

; ===== Step 4.1: Obtain Z Datum for Right Rear Hole =====
G4 S1
G1 Z{var.T1_Ref_Z + var.Z_Tilt+var.Z_Clearance} F18000

; =====Right Rear Bed Hole=====

; =====Obtain Z Datum=====
G90
G1 Z{var.T1_Ref_Z + var.Z_Tilt+var.Z_Clearance} F18000
G1 U{var.RR[0]} Y{var.RR[1] - var.hole_Z_Test_Offset} F18000

M98 P"0:/sys/nozzleprobe.g" Z10
G4 P300
set var.T1_Ref_Z = move.axes[2].userPosition

G90                                                    ; Absolute

G1 Z{var.T1_Ref_Z + 1} F6000                           ; Lift 1mm above bed surface
G1 Y{var.RR[1]} U{var.RR[0]} F6000                ; Move to the hole center position

; ===== Step 4.2: Right Rear Hole Center Positioning Test =====
; Test if nozzle is positioned above hole by attempting to dive into it
M558 K0 P8 C"1.io4.in" H5 F60 T18000               ; Configure probe: slow speed for safe diving
G38.4 K0 Z{var.T1_Ref_Z - var.Z_Dive} F60                 ; Attempt to dive 0.5mm below bed surface into hole

if result == 0  ; result==0 means probe did NOT trigger (hit bed surface, not in hole)
  ; Nozzle hit bed surface outside hole - not positioned correctly
  M98 P"0:/sys/led/pause.g"
  G90
  G1 Z{var.T1_Ref_Z + 1} F6000
  M291 R"Position Nozzle Above Hole" P"Nozzle is not positioned above the hole. Manually position the nozzle directly above the rear right hole center using U/Y jog controls." S3 U1 Y1
  
  ; Verify user positioned correctly by testing dive again
  M558 K0 P8 C"1.io4.in" H5 F60 T18000             ; Configure probe for verification
  G38.4 K0 Z{var.T1_Ref_Z - 1.0} F60               ; Dive deeper (1mm below surface) to verify
  if result == 0
    ; Still hitting surface outside hole - abort
    M98 P"0:/sys/led/fault.g"
    abort "Error: Nozzle still not positioned correctly above hole. Please check alignment."
  else
    ; Successfully positioned - update coordinates
    M98 P"0:/sys/led/resetstatus.g"
    G4 P300
    set var.RR[0] = move.axes[3].userPosition
    set var.RR[1] = move.axes[1].userPosition
else
  ; Nozzle went into hole successfully - already positioned correctly
  M98 P"0:/sys/led/resetstatus.g"
  G4 P300
  set var.RR[0] = move.axes[3].userPosition
  set var.RR[1] = move.axes[1].userPosition


; ===== Step 4.3: Right Rear Hole Center Searching (4-Direction Probing) =====
; Probe all 4 edges of the hole (YF, YR, UL, UR) to find precise center
; Repeats twice for accuracy refinement
M558 K0 P8 C"1.io4.in" H5 F60 T18000              ; define Z probe parameters
M98 P"0:/sys/user/actions/ProbeOffset.g"

set var.iteration = 0
while var.iteration < 2
  G90
  G1 U{var.RR[0]} Y{var.RR[1]} F6000
  
  ; 1st Probe - YF (Y Front/Negative)
  G38.4 K0 Y{move.axes[1].userPosition - var.max_Travel}
  M400
  G4 P300
  set var.holecoor[2] = move.axes[1].userPosition
  G1 Y{var.RR[1]} F6000
  
  ; 2nd Probe - YR (Y Rear/Positive)
  G38.4 K0 Y{move.axes[1].userPosition + var.max_Travel}
  M400
  G4 P300
  set var.holecoor[3] = move.axes[1].userPosition
  
  set var.RR[1] = {var.holecoor[2] + var.holecoor[3]} / 2 ; RRy center coordinate
  G1 Y{var.RR[1]} F6000
  
  ; 3rd Probe - UL (U Left/Negative)
  G38.4 K0 U{move.axes[3].userPosition - var.max_Travel}
  M400
  G4 P300
  set var.holecoor[0] = move.axes[3].userPosition
  G1 U{var.RR[0]} F6000
  
  ; 4th Probe - UR (U Right/Positive)
  G38.4 K0 U{move.axes[3].userPosition + var.max_Travel}
  M400
  G4 P300
  set var.holecoor[1] = move.axes[3].userPosition
  
  set var.RR[0] = {var.holecoor[0] + var.holecoor[1]} / 2 ; RRx center coordinate
  
  echo "=== Iteration " ^ {var.iteration + 1} ^ " Complete ==="
  echo "  holecoor[0] (UL) = " ^ var.holecoor[0]
  echo "  holecoor[1] (UR) = " ^ var.holecoor[1]
  echo "  holecoor[2] (YF) = " ^ var.holecoor[2]
  echo "  holecoor[3] (YR) = " ^ var.holecoor[3]
  echo "  RR[0] (U center) = " ^ var.RR[0]
  echo "  RR[1] (Y center) = " ^ var.RR[1]
  echo ""
  
  set var.iteration = var.iteration + 1

; ===== Step 4.4: Calculate Hole Diameter and Move Away =====
var holeR = abs(var.holecoor[0] - var.holecoor[1])
echo "Hole diameter (U axis) = " ^ var.holeR

G90
M400
G1 Y{var.RR[1]} U{var.RR[0]} F18000                      ; Move to final calculated center
G4 S1                                                      ; Wait 1 second
G1 Z{var.T1_Ref_Z + var.Z_Tilt+var.Z_Clearance} F18000   ; Lift to safe height


;===============================================================================
; SECTION 5: RIGHT FRONT HOLE PROBING
;===============================================================================

; ===== Step 5.1: Obtain Z Datum for Right Front Hole =====
G90
G1 U{var.RF[0]} Y{var.RF[1] + var.hole_Z_Test_Offset} F18000
G1 Z{var.T1_Ref_Z+var.Z_Clearance} F18000

M98 P"0:/sys/nozzleprobe.g" Z10
G4 P300
set var.T1_Ref_Z = move.axes[2].userPosition

G90                                                    ; Absolute

G1 Z{var.T1_Ref_Z + 1} F6000                           ; Lift 1mm above bed surface
G1 Y{var.RF[1]} U{var.RF[0]} F6000                ; Move to the hole center position

; ===== Step 5.2: Right Front Hole Center Positioning Test =====
; Test if nozzle is positioned above hole by attempting to dive into it
M558 K0 P8 C"1.io4.in" H5 F60 T18000               ; Configure probe: slow speed for safe diving
G38.4 K0 Z{var.T1_Ref_Z - var.Z_Dive} F60                 ; Attempt to dive 0.5mm below bed surface into hole

if result == 0  ; result==0 means probe did NOT trigger (hit bed surface, not in hole)
  ; Nozzle hit bed surface outside hole - not positioned correctly
  M98 P"0:/sys/led/pause.g"
  G90
  G1 Z{var.T1_Ref_Z + 1} F6000
  M291 R"Position Nozzle Above Hole" P"Nozzle is not positioned above the hole. Manually position the nozzle directly above the front right hole center using U/Y jog controls." S3 U1 Y1
  
  ; Verify user positioned correctly by testing dive again
  M558 K0 P8 C"1.io4.in" H5 F60 T18000             ; Configure probe for verification
  G38.4 K0 Z{var.T1_Ref_Z - 1.0} F60               ; Dive deeper (1mm below surface) to verify
  if result == 0
    ; Still hitting surface outside hole - abort
    M98 P"0:/sys/led/fault.g"
    abort "Error: Nozzle still not positioned correctly above hole. Please check alignment."
  else
    ; Successfully positioned - update coordinates
    M98 P"0:/sys/led/resetstatus.g"
    G4 P300
    set var.RF[0] = move.axes[3].userPosition
    set var.RF[1] = move.axes[1].userPosition
else
  ; Nozzle went into hole successfully - already positioned correctly
  M98 P"0:/sys/led/resetstatus.g"
  G4 P300
  set var.RF[0] = move.axes[3].userPosition
  set var.RF[1] = move.axes[1].userPosition


; ===== Step 5.3: Right Front Hole Center Searching (4-Direction Probing) =====
; Probe all 4 edges of the hole (YF, YR, UL, UR) to find precise center
; Repeats twice for accuracy refinement
M558 K0 P8 C"1.io4.in" H5 F60 T18000              ; define Z probe parameters
M98 P"0:/sys/user/actions/ProbeOffset.g"

set var.iteration = 0
while var.iteration < 2
  G90
  G1 U{var.RF[0]} Y{var.RF[1]} F6000
  
  ; 1st Probe - YF (Y Front/Negative)
  G38.4 K0 Y{move.axes[1].userPosition - var.max_Travel}
  M400
  G4 P300
  set var.holecoor[2] = move.axes[1].userPosition
  G1 Y{var.RF[1]} F6000
  
  ; 2nd Probe - YR (Y Rear/Positive)
  G38.4 K0 Y{move.axes[1].userPosition + var.max_Travel}
  M400
  G4 P300
  set var.holecoor[3] = move.axes[1].userPosition
  
  set var.RF[1] = {var.holecoor[2] + var.holecoor[3]} / 2 ; RFy center coordinate
  G1 Y{var.RF[1]} F6000
  
  ; 3rd Probe - UL (U Left/Negative)
  G38.4 K0 U{move.axes[3].userPosition - var.max_Travel}
  M400
  G4 P300
  set var.holecoor[0] = move.axes[3].userPosition
  G1 U{var.RF[0]} F6000
  
  ; 4th Probe - UR (U Right/Positive)
  G38.4 K0 U{move.axes[3].userPosition + var.max_Travel}
  M400
  G4 P300
  set var.holecoor[1] = move.axes[3].userPosition
  
  set var.RF[0] = {var.holecoor[0] + var.holecoor[1]} / 2 ; RFx center coordinate
  G1 U{var.RF[0]} F6000
  
  echo "=== Iteration " ^ {var.iteration + 1} ^ " Complete ==="
  echo "  holecoor[0] (UL) = " ^ var.holecoor[0]
  echo "  holecoor[1] (UR) = " ^ var.holecoor[1]
  echo "  holecoor[2] (YF) = " ^ var.holecoor[2]
  echo "  holecoor[3] (YR) = " ^ var.holecoor[3]
  echo "  RF[0] (U center) = " ^ var.RF[0]
  echo "  RF[1] (Y center) = " ^ var.RF[1]
  echo ""
  
  set var.iteration = var.iteration + 1

; ===== Step 5.4: Move Away and Return Bed to Level =====
G90
M400
G1 Y{var.RF[1]} U{var.RF[0]} F18000    ; Move to final calculated center
G4 S1                                    ; Wait 1 second
G1 Z50 F18000                            ; Lift to safe height


;===============================================================================
; SECTION 6: BED RESTORATION
;===============================================================================

; ===== Return Bed to Level Position =====
M400                        ; Wait for all moves to complete
M584 Z1.2                   ; Temporarily use only one Z motor
G91                         ; Relative positioning
G1 Z{-var.Z_Tilt} F18000    ; Lower bed by tilt amount (return to level)
G90                         ; Absolute positioning
M584 Z1.0:1.1:1.2           ; Restore all three Z motors
M906 X1800 U1800 Y1800:1800 Z850 E600:600 I35 T10
M913 Z100                   ; Restore Z motor current to 100%


;===============================================================================
; SECTION 7: CALCULATIONS AND CORRECTIONS
;===============================================================================

; ===== Step 7.1: Define Expected Dimensions =====
var CrossBarLength = 479.1      ; Distance for mechanical squaring correction calculation
var VertSpac       = 319.896    ; Y - Expected vertical distance (RR to RF)
var HorizSpac      = 300        ; X - Expected horizontal distance (LR to RR)

; ===== Step 7.2: Calculate Measured Distances (Hypotenuse) =====
var HorizMeasured = sqrt(pow(var.RR[0] - var.LR[0], 2) + pow(var.RR[1] - var.LR[1], 2))
var VertMeasured  = sqrt(pow(var.RF[0] - var.RR[0], 2) + pow(var.RF[1] - var.RR[1], 2))

; ===== Step 7.3: Extract X and Y Components from Measured Vectors =====
; The measured distances are hypotenuses - we need to project onto machine axes

; Horizontal edge (LR to RR) - primarily X-axis movement
var HorizDeltaU = var.RR[0] - var.LR[0]   ; U component (X-axis)
var HorizDeltaY = var.RR[1] - var.LR[1]   ; Y component

; Vertical edge (RR to RF) - primarily Y-axis movement  
var VertDeltaU = var.RF[0] - var.RR[0]    ; U component (X-axis)
var VertDeltaY = var.RF[1] - var.RR[1]    ; Y component

; ===== Step 7.4: Calculate Actual Axis Travel =====
; Extract the primary axis component from each measurement
var ActualXTravel = abs(var.HorizDeltaU)  ; X-axis travel from horizontal edge
var ActualYTravel = abs(var.VertDeltaY)   ; Y-axis travel from vertical edge

; ===== Step 7.5: Calculate Steps/mm Correction Factors =====
; Correction factor = Expected / Actual
var XStepsPerMmCorrection = var.HorizSpac / var.ActualXTravel
var YStepsPerMmCorrection = var.VertSpac / var.ActualYTravel

; ===== Step 7.6: Apply Corrections to Current Steps/mm =====
var CurrentXSteps = 400.0       ; Current X steps/mm setting
var CurrentYSteps = 400.0       ; Current Y steps/mm setting

var NewXSteps = var.CurrentXSteps * var.XStepsPerMmCorrection
var NewYSteps = var.CurrentYSteps * var.YStepsPerMmCorrection

; ===== Step 7.7: Calculate Axis Scaling Errors in Millimeters =====
var XErrorBefore = var.HorizSpac - var.ActualXTravel  ; How much X-axis is off
var YErrorBefore = var.VertSpac - var.ActualYTravel   ; How much Y-axis is off
var XErrorAfter = 0.0                                 ; After correction (theoretical)
var YErrorAfter = 0.0                                 ; After correction (theoretical)

; ===== Step 7.8: Calculate XY Squareness Error =====
; Use vector dot product to find angle between horizontal and vertical edges

; Edge vectors for squareness calculation
var Hx = var.RR[0] - var.LR[0]  ; Horizontal vector X component
var Hy = var.RR[1] - var.LR[1]  ; Horizontal vector Y component
var Vx = var.RF[0] - var.RR[0]  ; Vertical vector X component
var Vy = var.RF[1] - var.RR[1]  ; Vertical vector Y component

; Calculate angle between vectors using dot product
var dot = var.Hx * var.Vx + var.Hy * var.Vy
var lenH = sqrt(pow(var.Hx, 2) + pow(var.Hy, 2))
var lenV = sqrt(pow(var.Vx, 2) + pow(var.Vy, 2))
var angle = acos(var.dot / (var.lenH * var.lenV))
var alpha_deg = degrees(var.angle) - 90  ; Deviation from 90 degrees

; ===== Step 7.9: Calculate Mechanical Squaring Correction =====
; Calculate required crossbar adjustment using chord length formula
var CorrLength = 2 * var.CrossBarLength * sin(radians(abs(var.alpha_deg) / 2))
var mag = var.CorrLength/2

; Determine sign of correction (safe method without ternary operator)
var s = 1                       ; Default: +1
if var.alpha_deg >= 0
  set var.s = 0 - 1             ; If angle >= 0, use -1

; Apply safety factor (36%) and deadband (±1mm)
var CorrLengthSafety = var.mag * var.s * 0.36

if var.CorrLengthSafety < 0
  set var.CorrLengthSafety = var.CorrLengthSafety + 1  ; Add 1mm deadband
elif var.CorrLengthSafety > 0
  set var.CorrLengthSafety = var.CorrLengthSafety - 1  ; Subtract 1mm deadband

; ===== Step 7.10: Save Squaring Correction to Global Variable =====
set global.xySquareAuto = var.CorrLengthSafety

; ===== Step 7.11: Write Squaring Correction to File =====
echo >"0:/sys/user/variables/XySquareAuto.g" "set global.xySquareAuto = " ^ var.CorrLengthSafety

; ===== Step 7.12: Write Steps/mm Calibration to File (if enabled) =====
; Load the steps/mm calibration state
M98 P"0:/sys/user/variables/StepsCalibration.g"
M98 P"0:/sys/user/actions/StepsCalibration.g"

; Check if steps/mm calibration is enabled
if global.stepsCalibration == true
  ; ===== Calibration is ENABLED - Write calculated M92 values =====
  echo >"0:/sys/user/variables/StepsCalibration.g" "set global.stepsCalibration = true"
  echo >"0:/sys/user/actions/StepsCalibration.g" "M92 X" ^ var.NewXSteps ^ " Y" ^ var.NewYSteps ^ " U" ^ var.NewXSteps ^ " Z400 E400:400  ; calibrated values at "^ {state.time}
  
  echo "Steps/mm calibration values written to actions/StepsCalibration.g"
else
  echo "Steps/mm calibration is DISABLED - values not saved"


;===============================================================================
; SECTION 8: RESULTS DISPLAY
;===============================================================================

; ===== Step 8.1: Build Dialog Message Based on Enabled Calibrations =====
; Check if steps/mm calibration is enabled
var stepsCalEnabled = global.stepsCalibration == true

; Check if XY squaring is enabled (auto mode)
var squaringEnabled = global.xySquareMode == "auto"

; Build Axis Errors section
var msg1 = "<b>Axis Errors:</b>"
var msg2 = ""
if var.stepsCalEnabled
  set var.msg1 = var.msg1 ^ "<br>X: " ^ var.XErrorBefore ^ " mm → 0 mm ✓"
  set var.msg2 = "<br>Y: " ^ var.YErrorBefore ^ " mm → 0 mm ✓"
else
  set var.msg1 = var.msg1 ^ "<br>X: " ^ var.XErrorBefore ^ " mm (not saved - calibration disabled in settings)"
  set var.msg2 = "<br>Y: " ^ var.YErrorBefore ^ " mm (not saved - calibration disabled in settings)"

; Build Squareness section
var msg3 = ""
if var.squaringEnabled
  set var.msg3 = "<br><br><b>Squareness:</b><br>" ^ var.alpha_deg ^ "° → 0° ✓"
else
  set var.msg3 = "<br><br><b>Squareness:</b><br>" ^ var.alpha_deg ^ "° (not saved - XY squaring disabled in settings)"

var msgFull = var.msg1 ^ var.msg2 ^ var.msg3

; ===== Step 8.2: Display Comprehensive Results to Console =====
echo "===== XY AUTO SQUARING CALIBRATION RESULTS ====="
echo "Hole Center Coordinates:"
echo "  Left Rear:   U = " ^ var.LR[0] ^ ", Y = " ^ var.LR[1]
echo "  Right Rear:  U = " ^ var.RR[0] ^ ", Y = " ^ var.RR[1]
echo "  Right Front: U = " ^ var.RF[0] ^ ", Y = " ^ var.RF[1]
echo ""
echo "Measured Distances:"
echo "  Horizontal (Rear edge): " ^ var.HorizMeasured ^ " mm"
echo "  Vertical (Right edge): " ^ var.VertMeasured ^ " mm"
echo ""
echo "Axis Scaling Errors:"
echo "  X-axis: Expected " ^ var.HorizSpac ^ " mm, Measured " ^ var.ActualXTravel ^ " mm"
echo "    Error: " ^ var.XErrorBefore ^ " mm"
echo "  Y-axis: Expected " ^ var.VertSpac ^ " mm, Measured " ^ var.ActualYTravel ^ " mm"
echo "    Error: " ^ var.YErrorBefore ^ " mm"
echo ""
echo "Calculated Steps/mm Corrections:"
echo "  X: " ^ var.CurrentXSteps ^ " → " ^ var.NewXSteps ^ " steps/mm"
echo "  Y: " ^ var.CurrentYSteps ^ " → " ^ var.NewYSteps ^ " steps/mm"
echo ""
echo "Squareness Error:"
echo "  Angle Deviation: " ^ var.alpha_deg ^ "°"
echo ""
echo "Correction Values:"
echo "  Raw Correction: " ^ var.CorrLength ^ " mm"
echo "  Applied Correction (with safety): " ^ var.CorrLengthSafety ^ " mm"
echo "================================================"

; ===== Step 8.3: Display Summary Dialog to User =====
M291 S1 T0 R"XY Auto Squaring Complete" P{var.msgFull}


;===============================================================================
; END OF XY AUTO SQUARING CALIBRATION
;===============================================================================